<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Tianditu WMTS with optionsFromCapabilities</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol/ol.min.css">
    <style>
        body, html {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            font-family: Arial, sans-serif;
        }
        #map {
            width: 100%;
            height: 100%;
        }
        .info {
            position: absolute;
            bottom: 10px;
            left: 10px;
            background: rgba(255, 255, 255, 0.8);
            padding: 10px;
            border-radius: 5px;
            z-index: 100;
        }
        .loader {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: rgba(0, 0, 0, 0.7);
            color: white;
            padding: 15px;
            border-radius: 5px;
            z-index: 1000;
        }
    </style>
</head>
<body>
    <div id="map"></div>
    <div class="info">
        Tianditu WMTS with optionsFromCapabilities
    </div>
    <div id="loader" class="loader">Loading capabilities...</div>

    <script src="https://cdn.jsdelivr.net/npm/ol/dist/ol.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/proj4/dist/proj4.js"></script>
    <script>
        // Your Tianditu token (replace with your actual token)
        const TIANDITU_TOKEN = '';
        
        // Tianditu WMTS capabilities URLs
        const CAPABILITIES_URL = './WMTSCapabilities.xml';
        
        const epsg_4490 = 'EPSG:4490';
        proj4.defs(epsg_4490, 'GEOGCS["China Geodetic Coordinate System 2000",DATUM["China_2000",SPHEROID["CGCS2000",6378137,298.257222101,AUTHORITY["EPSG","1024"]],AUTHORITY["EPSG","1043"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4490"]]');
        ol.proj.proj4.register(proj4);
        ol.proj.get(epsg_4490).axisOrientation_ = 'neu';
        
        async function fetchCapabilities(url) {
            try {
                const response = await fetch(url);
                const text = await response.text();
                return new ol.format.WMTSCapabilities().read(text);
            } catch (error) {
                console.error('Error fetching capabilities:', error);
                throw error;
            }
        }
        
        function appendToken(url) {
            if (url?.indexOf('tk=') === -1) {
                url += (url.indexOf('?') === -1 ? '?' : '&') + 'tk=' + TIANDITU_TOKEN;
            }
            return url;
        }
        
        function getLayer(wmtsCap, layerName) {
            return wmtsCap.Contents.Layer?.find(l => l.Identifier == layerName)
        }
        
        function createLayersFromCapabilities(wmtsCap, layers, matrixSet = 'w') {
            try {
                return layers.map(l => {
                    const l_m = `${l}_${matrixSet}`;
                    const options = ol.source.WMTS.optionsFromCapabilities(wmtsCap, {
                        matrixSet: matrixSet,
                        layer: !getLayer(wmtsCap, l) && getLayer(wmtsCap, l_m) ? l_m : l
                    });
                    if (!options) throw new Error('Could not parse options from capabilities');
                    
                    const source = new ol.source.WMTS(options);
                    const originalTileUrlFunction = source.getTileUrlFunction();
                    source.setTileUrlFunction(t => appendToken(originalTileUrlFunction.call(source, t)));
                    
                    return new ol.layer.Tile({ source });
                })
            } catch (error) {
                console.error('Error creating layer:', error);
                throw error;
            }
        }
        
        async function initMap() {
            try {
                document.getElementById('loader').style.display = 'block';
                const cap = await fetchCapabilities(CAPABILITIES_URL);
                const map = new ol.Map({
                    target: 'map',
                    layers: createLayersFromCapabilities(cap, [ 'img', 'cia', 'ibo' ], 'c'),
                    view: new ol.View({
                        projection: epsg_4490,
                        center: [120.75,31.31],
                        zoom: 13
                    })
                });
                
                map.addControl(new ol.control.ScaleLine());
                document.getElementById('loader').style.display = 'none';
            } catch (error) {
                document.getElementById('loader').textContent = 'Error loading map: ' + error.message;
                console.error('Map initialization failed:', error);
            }
        }
        
        window.addEventListener('load', initMap);
    </script>
</body>
</html>